#include<stdio.h>
#include<string.h>                                                              
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/socket.h>
#include <netinet/in.h>
#include<stdlib.h>
#include <arpa/inet.h>
#include<sys/select.h>

#define SERPORT 8000
#define BUFSIZE 1024

int listenFdInit(int port)
{
    int sfd = socket(AF_INET,SOCK_STREAM,0);
    if(sfd==-1)
    {
        perror("socket error");
        exit(1);
    }

    struct sockaddr_in seraddr,cliaddr;
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(SERPORT);
    seraddr.sin_addr.s_addr=0;//任意IP

    //给套接字绑定IP和端口
    int ret = bind(sfd,(struct sockaddr*)&seraddr,sizeof(seraddr));
    if(ret==-1)
    {
        perror("bind error");
        exit(1);
    }
    
    //主动套接字转被动
    listen(sfd,66);
    return sfd;
}

void print_set(fd_set myset,int nfds)
{
    for(int i=0;i<nfds;i++)
    {
        if(FD_ISSET(i,&myset))
        {
            printf("1");
        }
        else
        {
            printf("0");
        }
    }
    printf("\n");
}

int main(int argc, char* argv[])
{
    int lfd = listenFdInit(SERPORT);
    //*************select*****************

    //将lfd交给select监听
    int nfds=-1;
    fd_set read_set,all_set;
    FD_ZERO(&all_set);
    FD_SET(lfd,&all_set);
    nfds=lfd+1;

    char buf[BUFSIZE];
    int selectRet;
    while(1)
    {
        read_set=all_set;
        //select返回值：触发了事件的文件描述符的总个数
        selectRet=select(nfds,&read_set,NULL,NULL,NULL);
        if(selectRet==-1)
        {
            perror("select error");
            exit(1);
        }
        printf("selectRet = %d\n",selectRet);
        print_set(read_set,nfds);
        //对监听套接字读事件的处理
        if(FD_ISSET(lfd,&read_set))
        {
            printf("lfd = %d , 读事件触发，马上处理\n",lfd);
            int cfd=accept(lfd,NULL,NULL);
            printf("客户端连接成功\n");
            if(cfd==-1)
            {
                perror("accept error");
                exit(1);
            }
            if(cfd>1023)
            {
                printf("too many client\n");
                exit(1);
            }
            //将cfd 放入
            FD_SET(cfd,&all_set);
            if(cfd>(nfds-1))
            {
                nfds=cfd+1;
            }
            if(--selectRet==0)
            {
                continue;
            }
        }
        //对通信套接字读事件的处理
        for(int i=lfd+1;i<nfds;i++)
        {
            if(FD_ISSET(i,&read_set))
            {
                int readRet = read(i,buf,BUFSIZE);
                if(readRet==-1)
                {
                    perror("read error");
                    exit(1);
                }
                else if(readRet==0)
                {
                    printf("有客户端退出\n");
                    close(i);
                    FD_CLR(i,&all_set);
                }
                else
                {
                    write(i,buf,readRet);
                    printf("*************************************\n");
                    write(STDOUT_FILENO,buf,readRet);
                    printf("*************************************\n");
                }
                if(--selectRet==0)
                {
                    break;
                }
            }
        }
    }   
    return 0;
}


